openssl: Introduce TLS PSK support#22057
Conversation
Add stream context options psk_client_cb and psk_server_cb that let clients and servers negotiate pre-shared key authentication on both TLS 1.2 and TLS 1.3. Callbacks return an Openssl\Psk instance carrying the key and, on clients, the identity, or null to refuse PSK. A new final Openssl\Psk class is added for that purpose, with readonly $psk and $identity properties and MAX_PSK_LEN / MAX_IDENTITY_LEN constants.
| zval client_cb; | ||
| zval server_cb; |
There was a problem hiding this comment.
You should store the callbacks as FCCs rather than zvals.
There was a problem hiding this comment.
We should address it in the follow up PR to cover sessions as well.
| } | ||
|
|
||
| ZVAL_UNDEF(&retval); | ||
| call_user_function(NULL, NULL, cb, &retval, argc, args); |
There was a problem hiding this comment.
Store the callback as a FCC and use zend_call_known_fcc() instead of call_user_function(), as this checks every single time if the zval is a callable, something that should be checked prior to saving it.
| if (!zend_is_callable_ex(callable, NULL, 0, NULL, NULL, &is_callable_error)) { | ||
| if (is_callable_error) { | ||
| zend_type_error("%s must be a valid callback, %s", | ||
| callback_name, is_callable_error); | ||
| efree(is_callable_error); | ||
| } else { | ||
| zend_type_error("%s must be a valid callback", callback_name); | ||
| } | ||
| return FAILURE; | ||
| } | ||
|
|
||
| if (!sslsock->psk_callbacks) { | ||
| sslsock->psk_callbacks = (php_openssl_psk_callbacks_t *)pemalloc( | ||
| sizeof(php_openssl_psk_callbacks_t), is_persistent); | ||
| ZVAL_UNDEF(&sslsock->psk_callbacks->client_cb); | ||
| ZVAL_UNDEF(&sslsock->psk_callbacks->server_cb); | ||
| sslsock->psk_callbacks->refcount = 1; | ||
| } |
There was a problem hiding this comment.
Instead of storing the callbacks as zvals, pass an FCC as a storage to zend_is_callable_ex()
| ZEND_PARSE_PARAMETERS_END(); | ||
|
|
||
| if (ZSTR_LEN(psk) == 0) { | ||
| zend_argument_value_error(1, "must not be empty"); |
There was a problem hiding this comment.
| zend_argument_value_error(1, "must not be empty"); | |
| zend_argument_must_not_be_empty_error(1); |
There was a problem hiding this comment.
Will be done in the follow up PR as well as you are picking it up
|
Gina is picking up the follow up bits so merging in this form as further improvements will be done seperately - they should be done in a separate PR as it applies to TLS session callback |
Adds pre-shared key authentication for OpenSSL streams, covering both TLS 1.2 (PSK ciphersuites) and TLS 1.3 (PSK as an external resumed session).
The
Openssl\Pskclass is following:Two new options under the
sslcontext:psk_client_cb:callable(resource $stream): ?Openssl\PskCalled on the client during the handshake to obtain the PSK and identity. Return
nullto decline PSK. The returnedPskmust have a non-null identity.psk_server_cb:callable(resource $stream, string $identity): ?Openssl\PskCalled on the server with the identity offered by the client. Return
nullto reject the identity. Only the key is read from the returnedPsk.For TLS 1.3 servers a default
session_id_contextis installed when the user does not supply one, since OpenSSL processes PSK as session resumption and would otherwise reject the constructedSSL_SESSIONwithSSL_R_SESSION_ID_CONTEXT_UNINITIALIZEDunder the defaultSSL_VERIFY_PEERconfiguration. An explicitsession_id_contextstill takes precedence.The RFC is not planned unless there are objections as it mirrors the previous Session proposal including all API decisions from it.